/*
 * Copyright(C) 2009, kesalin All rights reserved.
 * 
 * File name : UThreading.h
 * Brief     : Wrapper for Critical Section, Mutex, Event and Thread.
 * Version   : 1.0
 * Author    : kesalin@gmail.com
 * Date      : 2009-6-5
 */

#pragma once

#include "UCommon.h"

namespace LuoUtils {

/* */

// CritSec
class CritSec {

	CRITICAL_SECTION m_csec;

public:

	CritSec()
	{
		InitializeCriticalSection(&m_csec);
	}

	~CritSec()
	{
		DeleteCriticalSection(&m_csec);
	}

	void Lock()
	{
		EnterCriticalSection(&m_csec);
	}

	void Unlock()
	{
		LeaveCriticalSection(&m_csec);
	}

}; // CritSec

/* */

// AutoLock
template<class T> class AutoLock {

	T* m_p;

public:

	AutoLock(T* p) : m_p(p)
	{
		m_p->Lock();
	}

	~AutoLock()
	{
		m_p->Unlock();
	}

}; // AutoLock

/* */

// WaitHandle
class WaitHandle {

	HANDLE m_h;

public:

	WaitHandle() : m_h(0)
	{
	}

	~WaitHandle()
	{
		Close();
	}

	operator HANDLE() const
	{
		return m_h;
	}

	void Setup(HANDLE h)
	{
		Close();

		m_h = h;
	}

	void Close()
	{
		if (m_h != 0) {
			CloseHandle(m_h);
			m_h = 0;
		}
	}

	void Lock()
	{
		WaitForSingleObject(m_h, INFINITE);
	}

}; // WaitHandle

// Event
class Event : public WaitHandle {

public:

	HRESULT Create(bool bManualReset = true)
	{
		HANDLE h = CreateEventW(
			0,
			bManualReset ? TRUE : FALSE,
			FALSE,
			0);
		if (h == 0) {
			DWORD error = GetLastError();
			return HRESULT_FROM_WIN32(error);
		}

		Setup(h);

		return S_OK;
	}

	HRESULT Create(LPCWSTR name, bool bManualReset = true)
	{
		HANDLE h = CreateEventW(
			0,
			bManualReset ? TRUE : FALSE,
			FALSE,
			name);
		if (h == 0) {
			DWORD error = GetLastError();
			return HRESULT_FROM_WIN32(error);
		}

		Setup(h);

		return S_OK;
	}

	HRESULT Open(LPCWSTR name)
	{
		HANDLE h = OpenEventW(
			EVENT_ALL_ACCESS,
			FALSE,
			name);
		if (h == 0) {
			DWORD error = GetLastError();
			return HRESULT_FROM_WIN32(error);
		}

		Setup(h);

		return S_OK;
	}

	void SetEvent()
	{
		::SetEvent(*this);
	}

	void ResetEvent()
	{
		::ResetEvent(*this);
	}

	void Unlock()
	{
		::SetEvent(*this);
	}

}; // Event

// Mutex
class Mutex : public WaitHandle {

public:

	HRESULT Create(LPCWSTR name = 0)
	{
		HANDLE h = CreateMutexW(
			0,
			FALSE,
			name);
		if (h == 0) {
			DWORD error = GetLastError();
			return HRESULT_FROM_WIN32(error);
		}

		Setup(h);

		return S_OK;
	}

	void ReleaseMutex()
	{
		::ReleaseMutex(*this);
	}

	void Unlock()
	{
		::ReleaseMutex(*this);
	}

}; // Mutex

/* */

// URunnable
class URunnable {

public:

	virtual int STDCALL Run() = 0;

}; // URunnable

// Thread
class Thread {

	URunnable* m_pRunnable;

	HANDLE m_hThread;
	DWORD  m_idThread;

	int m_Code;

	Event m_ReadyEvent;

	CStringA m_Name;

public:

	Thread();
	~Thread();

	operator HANDLE() const
	{
		return m_hThread;
	}

	DWORD GetThreadId() const
	{
		return m_idThread;
	}

	int GetCode() const
	{
		return m_Code;
	}

	void SetupName(const char* p)
	{
		m_Name = p;
	}

	void Create(URunnable* run);

	void Close();

	int Join();

private:

	static unsigned STDCALL ThreadProc(void* p);

	unsigned OnThread();

}; // Thread

/* */

} // namespace LuoUtils

